

#include "libhash/include/list.h"
#include "native_list.h"

BEGIN_CLASS(NativeList);
    size_t _elem_size;
    lh_list_t* _list;
    char* _str;
END_CLASS(NativeList);


static void NativeList_ctor(NativeListClass* this, va_list* args)
{
    this->_elem_size = va_arg(*args, size_t);
    void (*free_hdlr)(void*) = NULL;

    switch(this->_elem_size)
    {
    case 1:
    case 2:
    case 4:
        break;
    case 8:
        free_hdlr = &free;
        break;
    default:
        raise("Element size not handled");
    }
    if ((this->_list = list_create(free_hdlr, NULL)) == NULL)
        raise("Out of memory");
}

static void NativeList_dtor(NativeListClass* this)
{
    list_free(this->_list);
}

static void NativeList_push_front(NativeListClass* this, va_list* args)
{
    int64_t *ptr;
    switch (this->_elem_size)
    {
    case 1:
    case 2:
    case 4:
        list_push(this->_list, (void*) va_arg(*args, int32_t));
        break;
    case 8:
        if ((ptr = malloc(sizeof(int64_t))) == NULL)
            raise("Out of memory");
        *ptr = va_arg(*args, int64_t);
        list_push(this->_list, ptr);
        break;
    default:
        raise("Element size not implemented");
    }
}

static void NativeList_push_back(NativeListClass* this, va_list* args)
{
int64_t *ptr;
    switch (this->_elem_size)
    {
    case 1:
    case 2:
    case 4:
        list_push_back(this->_list, (void*) va_arg(*args, int32_t));
        break;
    case 8:
        if ((ptr = malloc(sizeof(int64_t))) == NULL)
            raise("Out of memory");
        *ptr = va_arg(*args, int64_t);
        list_push_back(this->_list, ptr);
        break;
    default:
        raise("Element size not implemented");
    }
}

static size_t NativeList_size(NativeListClass* this)
{
    return this->_list->size;
}

static char const* NativeList_str(NativeListClass* this)
{
    (void) this;
    return "List";
}

static Object* NativeList_begin(NativeListClass* this)
{
    (void) this;
    raise("Not implemented");
    return NULL;
}

static Object* NativeList_end(NativeListClass* this)
{
    (void) this;
    raise("Not implemented");
    return NULL;
}

static Object* NativeList_front(NativeListClass* this)
{
    if (NativeList_size(this) == 0)
        raise("List is empty");
    return list_head(this->_list);
}

static Object* NativeList_back(NativeListClass* this)
{
    if (NativeList_size(this) == 0)
        raise("List is empty");
    return list_tail(this->_list);
}

IMPL_CONTAINER_CLASS(
    NativeList,
    &NativeList_ctor, &NativeList_dtor, &NativeList_str,
    NULL, NULL, NULL, NULL,
    NULL, NULL, NULL, // eq, gt, lt
    &NativeList_push_front,
    &NativeList_push_back,
    NULL, //pop_front
    NULL, //pop_back
    NULL, //append
    NULL, //erase
    NULL, //clear
    &NativeList_front,
    &NativeList_back,
    &NativeList_size,
    NULL, //setitem
    NULL, //getitem
    &NativeList_begin,
    &NativeList_end,
    0, // _elem_size
    NULL, // _list
    NULL // _str
);
